package com.hk.core.authentication.security.authentication.verifycode;

import com.hk.core.authentication.api.validatecode.image.ImageCodeProcessor;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;

import java.util.Objects;


/**
 * 验证码登录 配置
 */
@Setter
@RequiredArgsConstructor
public class VerifyCodeSecuritySecurityConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    private final ImageCodeProcessor imageCodeProcessor;

    private final SessionAuthenticationStrategy sessionAuthenticationStrategy;

    private final AuthenticationSuccessHandler successHandler;

    private final AuthenticationFailureHandler failureHandler;

    private String requestIdParamName;

    private String verifyCodeParamName;

    private RequestMatcher requestMatcher;

    @Override
    public void configure(HttpSecurity builder) {
        // 如果是基于session的配置，这里一定要设置 securityContextRepository，和 SecurityContextHolderFilter 的是同一个对象
        // 不然登录成功后，通过 org.springframework.security.web.context.SecurityContextHolderFilter 获取不到登录用户信息，又会跳转到登录页面
        // 默认的 UsernamePasswordAuthenticationFilter 有设置此属性，参考: org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer.configure中的 setSecurityContextRepository 代码
        var securityContextRepository = builder.getSharedObject(SecurityContextRepository.class);
        var filter = new VerifyCodeUsernamePasswordAuthenticationFilter(imageCodeProcessor);
        filter.setPostOnly(true);
        filter.setSecurityContextRepository(securityContextRepository);
        filter.setAuthenticationSuccessHandler(successHandler);
        filter.setAuthenticationFailureHandler(failureHandler);
        filter.setAllowSessionCreation(true);
        filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
        if (StringUtils.hasLength(requestIdParamName)) {
            filter.setVerifyCodeRequestId(requestIdParamName);
        }
        if (StringUtils.hasLength(verifyCodeParamName)) {
            filter.setVerifyCodeParamName(verifyCodeParamName);
        }
        if (Objects.nonNull(requestMatcher)) {
            filter.setRequiresAuthenticationRequestMatcher(requestMatcher);
        }
        filter.setAuthenticationManager(builder.getSharedObject(AuthenticationManager.class));
        filter.setRememberMeServices(builder.getSharedObject(RememberMeServices.class));
        builder.addFilterAfter(filter, UsernamePasswordAuthenticationFilter.class);
    }
}
